﻿using System.ComponentModel;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;

namespace SimpleTool.Server
{
    public static partial class RegExp
    {
        [GeneratedRegex("[\\s+]", RegexOptions.None)]
        public static partial Regex RegExpBlank();

        [GeneratedRegex("[^\n\r]", RegexOptions.None)]
        public static partial Regex RegExpUnEmpty();

        [GeneratedRegex("[\r\n]{4}", RegexOptions.None)]
        public static partial Regex RegExpEmpty4();

        [GeneratedRegex("[\\s\n\r]+", RegexOptions.None)]
        public static partial Regex RegExpEmpty();

        [GeneratedRegex("[\n\r]+", RegexOptions.None)]
        public static partial Regex RegExpWrapWork();

        [GeneratedRegex("\\s*,\\s*|\\s*、\\s*|\\s*&&\\s*", RegexOptions.None)]
        public static partial Regex RegExpMultiSpacing();

        [GeneratedRegex("\\s*&&\\s*", RegexOptions.None)]
        public static partial Regex RegExpAndSpacing();

        [GeneratedRegex("[0-9a-zA-Z]+", RegexOptions.IgnoreCase)]
        public static partial Regex RegExp0_9a_Z();

        [GeneratedRegex("[a-zA-Z]+", RegexOptions.IgnoreCase)]
        public static partial Regex RegExpa_Z();

        [GeneratedRegex("\\W+", RegexOptions.None)]
        public static partial Regex RegExpSpecial();

        [GeneratedRegex("[\\W_]+", RegexOptions.None)]
        public static partial Regex RegExpFileSpecial();

        [GeneratedRegex("\\d+", RegexOptions.None)]
        public static partial Regex RegExpNumber();

        [GeneratedRegex("(?-i)[MAC-]*((?:[0-9a-zA-Z]{2}[:-]+){4,}[0-9a-zA-Z]{2})\\W*(\\d+)*", RegexOptions.IgnoreCase)]
        public static partial Regex RegExpBlueMatch();

        [GeneratedRegex("[/|\\\\]", RegexOptions.None)]
        public static partial Regex RegExpSplitPath();

        [GeneratedRegex("(?=\\d)([0-9_]+\\W*)+", RegexOptions.None)]
        public static partial Regex RegExpDateMatch();

        [GeneratedRegex("[:-]", RegexOptions.None)]
        public static partial Regex RegExpBlueSeparator();

        [GeneratedRegex(@"(\d+[^\d\.a-zA-Z0-9]*)+", RegexOptions.None)]
        public static partial Regex RegExpTimeDetetor();

        [GeneratedRegex(@"\((.*)\)", RegexOptions.None)]
        public static partial Regex RegExpSqlColumns();

        [GeneratedRegex("(?-i)\\s*SELECT\\s*(.*)\\s*FROM", RegexOptions.None)]
        public static partial Regex RegExpSqlCountFormat();

        [GeneratedRegex("(COM.*\\d+)", RegexOptions.None)]
        public static partial Regex RegExpSerialCom();

    }

    public class Function
    {
        private string CacheOutputContent = string.Empty;

        private int CacheOutputMaxadd = 0;

        public static JsonSerializerOptions SafetyReferenceJsonOptions { get; } = new()
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, //  去除值为Null的属性
            ReferenceHandler = ReferenceHandler.Preserve, //  保护数据，保证引用数据可以正常序列化
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, //  获取一个编码器，保持原编码
            IncludeFields = true, //  包含字段
            WriteIndented = true, //  缩进美化
        };
        public async void FragmentProcessingFactory(string readContent, Action<string> IntactCallBack)
        {
            await Task.Run(() =>
            {
                int lenght = readContent.Length;
                int index = -1;
                MatchCollection matchs = RegExp.RegExpEmpty().Matches(readContent);
                if (matchs.Count > 0) index = matchs.Select(x => x.Index).Max();
                bool _end = index != -1 && index >= lenght - 3 && RegExp.RegExpUnEmpty().Match(readContent[index..]).Length == 0;

                if (_end || CacheOutputMaxadd >= 5)
                {
                    CacheOutputContent += readContent;
                    IntactCallBack.Invoke(CacheOutputContent);
                    CacheOutputContent = string.Empty;
                    CacheOutputMaxadd = 0;
                }
                else
                {
                    CacheOutputContent += readContent;
                    CacheOutputMaxadd++;
                }
            });
        }

        public static void Topmast()
        {
            Application.Current.MainWindow.Activate();
            Application.Current.MainWindow.Topmost = true;
            Application.Current.MainWindow.Topmost = false;
            Application.Current.MainWindow.Focus();
        }
    }

    public static class Visual
    {
        private readonly static Serilog.ILogger Logger = Serilog.Log.ForContext<VisualArg>();

        public enum VisualOrient
        {
            Top,
            Bottom
        }

        /// <summary>
        /// <para> VisualOrient Orient, ICollection[string] SourceNames, bool GetFirst, string ObjectName, bool Runstate</para>
        /// </summary>
        public class VisualArg
        {
            public VisualOrient Orient = VisualOrient.Bottom;

            public ICollection<string> SourceNames = [];

            public bool GetFirst = false;

            public string ObjectName = string.Empty;

            public bool Runstate = true;
        }

        public static async Task<object?> GetVisual<TKValueType>(this DependencyObject Source, VisualArg arg)
        {
            return await Source.GetVisual<TKValueType, TKValueType>(arg);
        }

        public static async Task<object?> GetVisual<TParent, TChild>(this DependencyObject Source, VisualArg arg)
        {
            ICollection<TChild> Collections = [];

            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                GetVisual<TParent, TChild>(Source, arg, Collections);
            });

            if (Collections.Count == 0)
            {
                if (arg.Orient == VisualOrient.Top)
                {
                    arg.Orient = VisualOrient.Bottom;
                }
                else if (arg.Orient == VisualOrient.Bottom)
                {
                    arg.Orient = VisualOrient.Top;
                }

                await Application.Current.Dispatcher.InvokeAsync(() =>
                {
                    GetVisual<TParent, TChild>(Source, arg, Collections);
                });
            }

            var Distinct = Collections.Distinct().ToList();

            if (Distinct.Count == 0)
            {
                return null;
            }
            else if (Distinct.Count == 1)
            {
                return Distinct.ElementAt(0);
            }
            else
            {
                return Collections;
            }
        }

        private static void GetVisual<TParent, TChild>(this DependencyObject Source, VisualArg arg, ICollection<TChild> Collection)
        {
            if (Source is not null)
            {
                if (Source is TChild _Child)
                {
                    if (arg.SourceNames.Count == 0)
                    {
                        Collection.Add(_Child);
                        if (arg.GetFirst)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }
                    else if (arg.SourceNames.Where(x => Source is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                            IEnumerable<string> _names && _names.Any())
                    {
                        Collection.Add(_Child);
                        if (arg.GetFirst || arg.SourceNames.Count <= 1)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }

                    DependencyObject Depedency;
                    if (arg.Orient == VisualOrient.Top)
                    {
                        Depedency = VisualTreeHelper.GetParent(Source);
                        VisualTree<TChild>(Depedency, Collection, arg);
                    }
                    else
                    {
                        for (int index = 0; index < VisualTreeHelper.GetChildrenCount(Source); index++)
                        {
                            if (arg.Runstate)
                            {
                                var BottomDependency = VisualTreeHelper.GetChild(Source, index);
                                VisualTree<TChild>(BottomDependency, Collection, arg);
                            }
                        }
                    }
                }
                else if (Source is TParent)
                {
                    VisualTree<TChild>(Source, Collection, arg);
                }
                else
                {
                    DependencyObject Depedency;

                    if (arg.Orient == VisualOrient.Top)
                    {
                        Depedency = VisualTreeHelper.GetParent(Source);
                        if (Depedency is TParent)
                        {
                            VisualTree(Depedency, Collection, arg);
                        }
                        else
                        {
                            GetVisual<TParent, TChild>(Depedency, arg, Collection);
                        }
                    }
                    else
                    {
                        for (int index = 0; index < VisualTreeHelper.GetChildrenCount(Source); index++)
                        {
                            if (arg.Runstate)
                            {
                                var BottomDependency = VisualTreeHelper.GetChild(Source, index);

                                if (BottomDependency is TParent)
                                {
                                    VisualTree(BottomDependency, Collection, arg);
                                }
                                else
                                {
                                    GetVisual<TParent, TChild>(BottomDependency, arg, Collection);
                                }
                            }
                        }
                    }
                }
            }
        }

        private static void VisualTree<TChild>(DependencyObject Source, ICollection<TChild> Collection, VisualArg arg)
        {
            void LoopChild(DependencyObject obj)
            {
                for (int index = 0; index < VisualTreeHelper.GetChildrenCount(obj); index++)
                {
                    var children = VisualTreeHelper.GetChild(obj, index);

                    if (children is TChild RealSource)
                    {
                        if (arg.SourceNames.Count == 0)
                        {
                            Collection.Add(RealSource);
                            if (arg.GetFirst)
                            {
                                arg.Runstate = false;
                                return;
                            }
                            else
                            {
                                VisualTree<TChild>(children, Collection, arg);
                            }

                        }
                        else
                        {
                            if (arg.SourceNames.Where(x => obj is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                                IEnumerable<string> _names && _names.Any())
                            {
                                Collection.Add(RealSource);
                                if (arg.GetFirst || arg.SourceNames.Count <= 1)
                                {
                                    arg.Runstate = false;
                                    return;
                                }
                            }
                            else
                            {
                                VisualTree<TChild>(children, Collection, arg);
                            }
                        }
                    }
                    else
                    {
                        VisualTree<TChild>(children, Collection, arg);
                    }
                }
            }

            if (Source != null)
            {
                if (Source is TChild _Source)
                {
                    if (arg.SourceNames.Count == 0)
                    {
                        Collection.Add(_Source);
                        if (arg.GetFirst)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }
                    else
                    {
                        if (arg.SourceNames.Where(x => Source is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                        IEnumerable<string> _names && _names.Any())
                        {
                            Collection.Add(_Source);
                            if (arg.GetFirst || arg.SourceNames.Count <= 1)
                            {
                                arg.Runstate = false;
                                return;
                            }
                        }
                        else
                        {
                            LoopChild(Source);
                            if (arg.GetFirst || arg.SourceNames.Count <= 1)
                            {
                                arg.Runstate = false;
                                return;
                            }
                        }
                    }
                }
                else
                {
                    LoopChild(Source);
                    if (arg.GetFirst || arg.SourceNames.Count <= 1)
                    {
                        arg.Runstate = false;
                        return;
                    }
                }
            }
        }

        public static async Task<object?> GetLogical<KValueType>(this DependencyObject Source, VisualArg arg)
        {
            return await Source.GetLogical<KValueType, KValueType>(arg);
        }

        public static async Task<object?> GetLogical<Parent, Child>(this DependencyObject Source, VisualArg arg)
        {
            ICollection<Child> Collections = [];

            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                GetLogical<Parent, Child>(Source, arg, Collections);
            });

            if (Collections.Count == 0)
            {
                if (arg.Orient == VisualOrient.Top)
                {
                    arg.Orient = VisualOrient.Bottom;
                }
                else if (arg.Orient == VisualOrient.Bottom)
                {
                    arg.Orient = VisualOrient.Top;
                }

                await Application.Current.Dispatcher.InvokeAsync(() =>
                {
                    GetLogical<Parent, Child>(Source, arg, Collections);
                });
            }

            var Distinct = Collections.Distinct().ToList();

            if (Distinct.Count == 0)
            {
                return null;
            }
            else if (Distinct.Count == 1)
            {
                return Distinct.ElementAt(0);
            }
            else
            {
                return Collections;
            }
        }

        private static void GetLogical<TParent, TChild>(this DependencyObject Source, VisualArg arg, ICollection<TChild> Collection)
        {
            if (Source is not null)
            {
                if (Source is TChild _Child)
                {
                    if (arg.SourceNames.Count == 0)
                    {
                        Collection.Add(_Child);
                        if (arg.GetFirst)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }
                    else if (arg.SourceNames.Where(x => Source is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                            IEnumerable<string> _names && _names.Any())
                    {
                        Collection.Add(_Child);
                        if (arg.GetFirst || arg.SourceNames.Count <= 1)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }

                    DependencyObject Depedency;
                    if (arg.Orient == VisualOrient.Top)
                    {
                        Depedency = LogicalTreeHelper.GetParent(Source);
                        LogicalTree<TChild>(Depedency, Collection, arg);
                    }
                    else
                    {
                        foreach (var unit in LogicalTreeHelper.GetChildren(Source))
                        {
                            if (arg.Runstate)
                            {
                                if (unit is not null and DependencyObject _dp)
                                {
                                    LogicalTree<TChild>(_dp, Collection, arg);
                                }
                            }
                        }
                    }
                }
                else if (Source is TParent)
                {
                    LogicalTree(Source, Collection, arg);
                }
                else
                {
                    DependencyObject Depedency;

                    if (arg.Orient == VisualOrient.Top)
                    {
                        Depedency = LogicalTreeHelper.GetParent(Source);
                        if (Depedency is TParent)
                        {
                            LogicalTree(Depedency, Collection, arg);
                        }
                        else
                        {
                            GetLogical<TParent, TChild>(Depedency, arg, Collection);
                        }
                    }
                    else
                    {
                        foreach (var unit in LogicalTreeHelper.GetChildren(Source))
                        {
                            if (arg.Runstate)
                            {
                                if (unit is not null and DependencyObject _dp)
                                {
                                    if (_dp is TParent _Parent)
                                    {
                                        LogicalTree(_dp, Collection, arg);
                                    }
                                    else
                                    {
                                        GetLogical<TParent, TChild>(_dp, arg, Collection);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private static void LogicalTree<TChild>(DependencyObject Source, ICollection<TChild> Collection, VisualArg arg)
        {
            void LoopChild(DependencyObject obj)
            {
                foreach (var unit in LogicalTreeHelper.GetChildren(obj))
                {
                    if (unit is not null and DependencyObject _dp)
                    {
                        if (_dp is TChild RealSource)
                        {
                            if (arg.SourceNames.Count == 0)
                            {
                                Collection.Add(RealSource);
                                if (arg.GetFirst)
                                {
                                    arg.Runstate = false;
                                    return;
                                }
                                else
                                {
                                    LogicalTree<TChild>(_dp, Collection, arg);
                                }

                            }
                            else
                            {
                                if (arg.SourceNames.Where(x => obj is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                                    IEnumerable<string> _names && _names.Any())
                                {
                                    Collection.Add(RealSource);
                                    if (arg.GetFirst || arg.SourceNames.Count <= 1)
                                    {
                                        arg.Runstate = false;
                                        return;
                                    }
                                }
                                else
                                {
                                    LogicalTree(_dp, Collection, arg);
                                }
                            }
                        }
                        else
                        {
                            LogicalTree(_dp, Collection, arg);
                        }
                    }
                }
            }

            if (Source != null)
            {
                if (Source is TChild _Source)
                {
                    if (arg.SourceNames.Count == 0)
                    {
                        Collection.Add(_Source);
                        if (arg.GetFirst)
                        {
                            arg.Runstate = false;
                            return;
                        }
                    }
                    else
                    {
                        if (arg.SourceNames.Where(x => Source is FrameworkElement _FrameworkElement && _FrameworkElement.Name == x) is not null and
                        IEnumerable<string> _names && _names.Any())
                        {
                            Collection.Add(_Source);
                            if (arg.GetFirst || arg.SourceNames.Count <= 1)
                            {
                                arg.Runstate = false;
                                return;
                            }
                        }
                        else
                        {
                            LoopChild(Source);
                            if (arg.GetFirst || arg.SourceNames.Count <= 1)
                            {
                                arg.Runstate = false;
                                return;
                            }
                        }
                    }
                }
                else
                {
                    LoopChild(Source);
                    if (arg.GetFirst || arg.SourceNames.Count <= 1)
                    {
                        arg.Runstate = false;
                        return;
                    }
                }
            }
        }
    }

    public sealed class Ruined
    {
        private FrameworkElement? Element = null;

        private Window? MainWindow = null;

        private bool _disposed = false;

        private readonly Action? AshbinBack = null;

        private readonly Func<Task<bool>>? ClosingBack = null;

        private readonly Serilog.ILogger logger = Serilog.Log.ForContext<Ruined>();

        public Ruined(FrameworkElement Frame, Action Ashbin, Func<Task<bool>>? closingBack = null)
        {
            Element = Frame;
            AshbinBack = Ashbin;
            Frame.Loaded += CompleteLoaded;
            ClosingBack = closingBack;
        }

        public void CompleteLoaded(object? sender, RoutedEventArgs e)
        {
            MainWindow = Window.GetWindow(Element);
            if (MainWindow is not null)
            {
                MainWindow.Closing += WindowClosingEvent;
                MainWindow.Closed += WindowClosedEvent;
            }
        }

        private async void WindowClosingEvent(object? sender, CancelEventArgs e)
        {
            e.Cancel = true;

            if (MainWindow is not null) MainWindow.Closing -= WindowClosingEvent;

            if (ClosingBack is not null)
            {
                await ClosingBack.Invoke();

                MainWindow?.Close();
            }
        }

        private void WindowClosedEvent(object? sender, EventArgs e)
        {
            if (MainWindow is not null &&
                Element is not null)
            {
                if (!_disposed)
                {
                    if (Element != null)
                    {
                        Element.Loaded -= CompleteLoaded;
                    }
                    if (MainWindow != null)
                    {
                        MainWindow.Closed -= WindowClosedEvent;
                    }

                    Element = null;

                    MainWindow = null;

                    _disposed = true;

                    AshbinBack?.Invoke();

                    logger.Print(RuntimeLog.LogType.Warning, $"{Element?.GetType().Name} released, win closed");

                }
            }
        }
    }
}
